package com.dwd.user.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.dwd.basic.constant.PetLoginConstant;
import com.dwd.basic.constant.VerificationConstant;
import com.dwd.basic.exception.CustomException;
import com.dwd.basic.service.impl.BaseServiceImpl;
import com.dwd.basic.utils.AjaxResult;
import com.dwd.basic.utils.HttpClientUtils;
import com.dwd.user.constant.WeChatConstant;
import com.dwd.user.mapper.LoginInfoMapper;
import com.dwd.user.mapper.UserMapper;
import com.dwd.user.mapper.WeChatMapper;
import com.dwd.user.pojo.LoginInfo;
import com.dwd.user.pojo.User;
import com.dwd.user.pojo.WeChat;
import com.dwd.user.pojo.dto.LoginInfoDto;
import com.dwd.user.service.IWeChatService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @Description: TODO
 * @Author 汶狄
 * @Date 2021/1/19 17:35
 * @Version 1.0
 */
@Service
public class WeChatServiceImpl extends BaseServiceImpl<WeChat> implements IWeChatService {
    @Autowired
    private WeChatMapper weChatMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private LoginInfoMapper loginInfoMapper;
    @Autowired
    private UserMapper userMapper;

    /**
     * 处理回调
     * @param code
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> handlCallback(String code) {
        Map<String, Object> map = new HashMap<>(16);
        //通过code获取access_token
        String tokenUrl = WeChatConstant.ACCESS_TOKEN_URI.replace("APPID", WeChatConstant.APPID)
                .replace("SECRET", WeChatConstant.SECRET)
                .replace("CODE", code);
        //发起请求
        String token = HttpClientUtils.httpGet(tokenUrl);
        //转为json对象
        JSONObject jsonObject = JSONObject.parseObject(token);
        //获取token
        String access_token = jsonObject.getString("access_token");
        //微信用户唯一标识
        String openid = jsonObject.getString("openid");
        //只需要两个参数,发起请求的地址
        String userinfo_url = WeChatConstant.USERINFO_URL.replace("ACCESS_TOKEN", access_token).replace("OPENID", openid);
        //发送请求,获取用户个人信息
        String userInfo = HttpClientUtils.httpGet(userinfo_url);
        //转为json对象
        JSONObject userInfoObj = JSONObject.parseObject(userInfo);
        //通过openid查找是否有数据，t_wxuser 和 t_logininfo，为什么联表，因为会判断logininfo是否为空，需要映射logininfo，所以联表查询出来映射
        WeChat weChat = weChatMapper.queryWeChatByOpenId(openid);
        //如果没有，说明第一次扫码
        if (weChat == null) {
            weChat = new WeChat();
            //给wechat设置值，没有设置logininfo
            weChat.setHeadimgurl(userInfoObj.getString("headimgurl"))
                    .setNickname(userInfoObj.getString("nickname"))
                    .setOpenid(userInfoObj.getString("openid"))
                    .setSex(userInfoObj.getInteger("sex"))
                    .setAddress(userInfoObj.getString("country") +
                            userInfoObj.getString("province") +
                            userInfoObj.getString("city"));
            //存入t_wxuser
            weChatMapper.save(weChat);
            //第一次扫码肯定没有绑定,返回true，前端根据状态跳转绑定界面
            map.put("openid", openid);
            return map;
        } else {
            //判断LoginInfo是否为空
            if (weChat.getLoginInfo() != null) {
                //说明绑定过了,存入redis,返回token和user,响应状态，直接登陆，
                //生成随机token
                String token1 = UUID.randomUUID().toString();
                //存入redis 30分钟
                redisTemplate.opsForValue().set(token1, weChat.getLoginInfo(), 30, TimeUnit.MINUTES);
                //响应给前端
                map.put("token", token1);
                map.put("user", weChat.getLoginInfo());
            } else {
                //没有绑定
                map.put("openid", openid);
            }
            return map;
        }
    }

    /**
     * 绑定手机
     *
     * @param loginInfoDto 临时存储数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> binder(LoginInfoDto loginInfoDto) throws CustomException {
        Map<String, Object> map = new HashMap<>(16);
        //校验数据
        checkBinderData(loginInfoDto);
        //查询该手机是否存在logininfo表中
        LoginInfo loginInfo = loginInfoMapper.queryByUsernameAndType(loginInfoDto.getPhone(), loginInfoDto.getType());
        //存在 绑定微信 直接登陆
        if (loginInfo != null) {
            //根据openid绑定账号
            weChatMapper.updateByOpenId(loginInfo.getId(), loginInfoDto.getOpenid());
            //存入redis 30分钟
            String token = UUID.randomUUID().toString();
            redisTemplate.opsForValue().set(token, loginInfo, 30, TimeUnit.MINUTES);
            //返回token user
            map.put("token", token);
            map.put("user", loginInfo);
        } else {
            //不存在
            //创建loginInfo对象
            LoginInfo loginInfo1 = createLoginInfo(loginInfoDto);
            //存入logininfo
            loginInfoMapper.save(loginInfo1);
            //创建user
            User user = createUser(loginInfo1);
            //存入user
            userMapper.save(user);
            //根据openid绑定账号
            weChatMapper.updateByOpenId(loginInfo1.getId(), loginInfoDto.getOpenid());
            //存入redis 30分钟
            String token = UUID.randomUUID().toString();
            redisTemplate.opsForValue().set(token, loginInfo, 30, TimeUnit.MINUTES);
            //返回token user
            map.put("token", token);
            map.put("user", loginInfo1);
        }
        return map;
    }

    /**
     * 校验绑定数据
     *
     * @param loginInfoDto
     */
    public void checkBinderData(LoginInfoDto loginInfoDto) throws CustomException {
        //手机不能为空
        if (StringUtils.isEmpty(loginInfoDto.getPhone())) {
            throw new CustomException("手机号不能为空");
        }
        //手机号码是否正确
        String Regex = "(?:(?:(?:13[0-9])|(?:14[57])|(?:15[0-35-9])|(?:19[0-35-9])|(?:17[36-8])|(?:18[0-9]))\\d{8})|(?:170[057-9]\\d{7})";
        if (!loginInfoDto.getPhone().matches(Regex)) {
            throw new CustomException("请输入正确的手机号");
        }
        //验证码不能为空
        if (StringUtils.isEmpty(loginInfoDto.getCode())) {
            throw new CustomException("验证码不能为空");
        }
        //获取验证码 GBCG:1611064055506
        String value = (String) redisTemplate.opsForValue().get(loginInfoDto.getPhone() + ":" + VerificationConstant.WECHAT_BINDER);
        //验证码是否过期
        if (StringUtils.isEmpty(value)) {
            throw new CustomException("验证码过期");

        }
        //验证码是否正确
        if (!loginInfoDto.getCode().toLowerCase().equals(value.split(":")[0].toLowerCase())) {
            throw new CustomException("验证码错误");
        }
    }

    /**
     * 创建user，用来存到user表
     *
     * @param loginInfo
     * @return
     */
    private User createUser(LoginInfo loginInfo) {
        User user = new User();
        BeanUtils.copyProperties(loginInfo, user);
        //设置状态
        user.setState(PetLoginConstant.HOME);
        //设置logininfo
        user.setLoginInfo(loginInfo);
        return user;
    }

    /**
     * 创建LoginInfo，用来存到LoginInfo表
     *
     * @param loginInfoDto
     * @return
     */
    private LoginInfo createLoginInfo(LoginInfoDto loginInfoDto) {
        LoginInfo loginInfo = new LoginInfo();
        loginInfo.setType(loginInfoDto.getType()).setPhone(loginInfoDto.getPhone());
        return loginInfo;
    }
}
